/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.control;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.zhiqim.kernel.paging.PageBuilder;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Lists;

/**
 * 消息队列,对LinkedList进行封装，增加对象锁对队列进行控制：<br><br>
 *  1)当列表中没有数据时阻塞到队列中读取消息的线程
 *  2)当列表中新增数据时通知所有正在阻塞的线程
 *  
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class Queue<E> implements Serializable
{
    private static final long serialVersionUID = 1L;
    
    private final QueueLock lock = new QueueLock();
    private final LinkedList<E> list = new LinkedList<E>();

    /** 投递对象，默认从后端排队 */
    public void post(E e)
    {
        post(e, false);
    }
    
    /** 投递对象，优先的投放到前端，非优先投放后端 */
    public void post(E e, boolean priority)
    {
        if (e == null)
            return;
        
        synchronized (list)
        {
            if (priority)
                list.addFirst(e);
            else
                list.add(e);
        }
        
        if (list.size() <= 1)
            lock.unlock();
        else
            lock.unlockAll();
    }
    
    /**
     * 接收消息队列中的对象，如果当前没有则阻塞线程等待指定时间，
     * 如果等待时间内有通知则读取，等待结束再尝试一次，未读到返回NULL
     * 
     * @param timeout 等待时间，以毫秒为单位
     * @return 如果有消息，则返回消息，如果没有则返回null
     */
    public E accept(long timeout)
    {
        synchronized (list)
        {
            if (!list.isEmpty())
                return list.removeFirst();
        }

        lock.lock(timeout);
        
        synchronized (list)
        {
            if (list.isEmpty())
                return null;
            return list.removeFirst();
        }
    }

    /** 对象是否存在对列中 */
    public boolean contains(E e)
    {
        return list.contains(e);
    }
    
    /** 当前对列是否为空 */
    public boolean isEmpty()
    {
        return list.isEmpty();
    }
    
    /** 清除队列消息 */
    public void clear()
    {
        synchronized (list)
        {
            list.clear();
        }
    }
    
    /** 获取当前队列长度 */
    public int size()
    {
        return list.size();
    }
    
    /** 获取当前队列的一个拷贝 */
    public List<E> copy()
    {
        return Lists.copy(list, true);
    }
    
    /** 获取消息分页列表，注意根据index读取有可能有重复，仅供参考 */
    public PageResult<E> list(int pageNo, int pageSize)
    {
        Asserts.as((pageNo > 0 && pageSize > 0)?null:"页码必须大于0");
        
        int formIndex = (pageNo-1) * pageSize;
        int toIndex = pageNo * pageSize;
        
        List<E> li = new ArrayList<>(pageSize);
        for (int i=formIndex;i<toIndex;i++)
        {
            if (i >= list.size())
                break;
            
            try{li.add(list.get(i));}catch(IndexOutOfBoundsException e){break;}
        }

        return PageBuilder.newResult(list.size(), pageNo, pageSize, Collections.unmodifiableList(li));
    }
}